﻿using GMap.NET;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization;
using YamlDotNet.Core;
using static GMap.NET.Entity.OpenStreetMapGeocodeEntity;
using OsmSharp.Streams;
using System.IO.Pipes;
using NetTopologySuite.Features;
using NetTopologySuite.Geometries;
using OsmSharp;
using OsmSharp.Geo;
using OsmSharp.API;
using GMap.NET.WindowsForms.Markers;
using GMap.NET.WindowsForms;
using GMapMarkerExt.Markers;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using GeoAPI.Geometries;
using GalaSoft.MvvmLight;
using System.Collections.ObjectModel;
using static GMap.NET.Entity.OpenStreetMapGraphHopperRouteEntity;

namespace RailYardMarker
{
    public partial class MainForm : Form
    {
        private GMapOverlay nodeLayer;
        private GMapOverlay osmLayer;
        private MainFormViewModel _vm;
        private bool _showMarkText = true;
        private Dictionary<Yard, TreeNode> _yardNodeDict = new Dictionary<Yard, TreeNode>();

        public MainForm()
        {
            InitializeComponent();
            _vm = new MainFormViewModel();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this._vm.PropertyChanged += _vm_PropertyChanged;

            _vm.OnYardLoaded += ViewModel_OnYardLoaded;
            _vm.OnCurrentYardChanged += ViewModel_OnCurrentYardChanged;
            _vm.OnYardInfoChanged += ViewModel_OnYardInfoChanged; ;
            //Bind Treeview to viewmodel
            _vm.OnYardPointAdded += ViewModel_OnPointAdded;
            _vm.OnYardPointUpdated += ViewModel_OnYardPointUpdated;
            _vm.OnYardPointDeleted += ViewModel_OnYardPointDeleted;

            _vm.OnYardConnectionAdded += ViewModel_OnYardConnectionAdded;
            _vm.OnYardConnectionUpdated += ViewModel_OnYardConnectionUpdated;
            _vm.OnYardConnectionDeleted += ViewModel_OnYardConnectionDeleted;

            _vm.OnYardBoundaryPointAdded += ViewModel_OnYardBoundaryPointAdded;
            _vm.OnYardBoundaryPointUpdated += ViewModel_OnYardBoundaryPointUpdated;
            _vm.OnYardBoundaryPointDeleted += ViewModel_OnYardBoundaryPointDeleted;

            _vm.OnYardSubYardAddedd += ViewModel_OnYardSubYardAddedd;
            _vm.OnYardSubYardDeleted += ViewModel_OnYardSubYardDeleted;
        }

        private void _vm_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if(e.PropertyName == "CurYardName")
            {
                this.Selected_Yard.Text = this._vm.CurYardName;
            }
        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            InitMap();
            gMapControl1.MapProvider = GMap.NET.MapProviders.BingOSMapProvider.Instance;
            GMaps.Instance.Mode = AccessMode.ServerAndCache;
            this.gMapControl1.DragButton = MouseButtons.Right;
            this.gMapControl1.Position = new PointLatLng(40.0, 117.0);
            this.gMapControl1.Zoom = 14;
            this.gMapControl1.MouseWheelZoomEnabled = true;
            this.gMapControl1.MouseWheelZoomType = MouseWheelZoomType.MousePositionWithoutCenter;
            this.gMapControl1.ShowCenter = true;
            gMapControl1.Refresh();
        }

        #region Handle ViewModel Events
        private void ViewModel_OnYardLoaded(object sender, EventArgs e)
        {
            Draw_TreeView(_vm.Yard);
        }
        private void ViewModel_OnCurrentYardChanged(object sender, EventArgs e)
        {
            if(this._vm.CurYard != null)
            {
                Draw_Yard_Click(null, null);
            }

        }
        private void ViewModel_OnYardInfoChanged(object sender, YardInfoEventArgs e)
        {
            //Find Node of yard
            TreeNode node = _yardNodeDict[e.Yard];

            //Update
            node.Text = ($"Yard {e.Yard.Info.Name} {e.Yard.Info.Id}");

        }
        private void ViewModel_OnPointAdded(object sender, PointEventArgs e)
        {
            //Find Node of yard
            TreeNode node = _yardNodeDict[e.Yard].Nodes["Points"];

            //Update
            var p = e.Point;
            var sub_node = node.Nodes.Add(p.ToString());
            sub_node.Tag = p;
            
            treeView1.SelectedNode = sub_node;
            propertyGrid1.SelectedObject = p;
            Draw_Yard_Click(null, null);
        }
        private void ViewModel_OnYardPointDeleted(object sender, PointEventArgs e)
        {
            //Find Node of yard
            TreeNode node = _yardNodeDict[e.Yard].Nodes["Points"];

            //Update
            int index = e.Index;
            node.Nodes.RemoveAt(index);

            treeView1.SelectedNode = null;
            propertyGrid1.SelectedObject = null;
            Draw_Yard_Click(null, null);
        }
        private void ViewModel_OnYardPointUpdated(object sender, PointEventArgs e)
        {
            //Find Node of yard
            TreeNode node = _yardNodeDict[e.Yard].Nodes["Points"];

            //Update
            //Update
            int index = e.Index;
            var subNode = node.Nodes[index];
            subNode.Text = e.Point.ToString();
            Draw_Yard_Click(null, null);
        }
        private void ViewModel_OnYardConnectionAdded(object sender, ConnectionEventArgs e)
        {
            //Find Node of yard
            TreeNode node = _yardNodeDict[e.Yard].Nodes["Connections"];

            //Update
            var p = e.Connection;
            var sub_node = node.Nodes.Add(p.ToString());
            sub_node.Tag = p;

            treeView1.SelectedNode = sub_node;
            propertyGrid1.SelectedObject = p;
            Draw_Yard_Click(null, null);
        }
        private void ViewModel_OnYardConnectionDeleted(object sender, ConnectionEventArgs e)
        {
            //Find Node of yard
            TreeNode node = _yardNodeDict[e.Yard].Nodes["Connections"];

            //Update
            int index = e.Index;
            node.Nodes.RemoveAt(index);

            treeView1.SelectedNode = null;
            propertyGrid1.SelectedObject = null;
            Draw_Yard_Click(null, null);
        }
        private void ViewModel_OnYardConnectionUpdated(object sender, ConnectionEventArgs e)
        {
            //Find Node of yard
            TreeNode node = _yardNodeDict[e.Yard].Nodes["Connections"];

            //Update
            //Update
            int index = e.Index;
            var subNode = node.Nodes[index];
            subNode.Text = e.Connection.ToString();
            Draw_Yard_Click(null, null);
        }
        private void ViewModel_OnYardBoundaryPointAdded(object sender, BoundaryEventArgs e)
        {
            //Find Node of yard
            TreeNode node = _yardNodeDict[e.Yard].Nodes["Boundary"];

            //Update
            var p = e.Boundary;
            var sub_node = node.Nodes.Add(p.ToString());
            sub_node.Tag = p;
            Draw_Yard_Click(null, null);
        }
        private void ViewModel_OnYardBoundaryPointUpdated(object sender, BoundaryEventArgs e)
        {
            //Find Node of yard
            TreeNode node = _yardNodeDict[e.Yard].Nodes["Boundary"];

            //Update
            //Update
            int index = e.Index;
            var subNode = node.Nodes[index];
            subNode.Text = e.Boundary.ToString();
            Draw_Yard_Click(null, null);
        }
        private void ViewModel_OnYardBoundaryPointDeleted(object sender, BoundaryEventArgs e)
        {
            //Find Node of yard
            TreeNode node = _yardNodeDict[e.Yard].Nodes["Boundary"];

            //Update
            int index = e.Index;
            node.Nodes.RemoveAt(index);
            Draw_Yard_Click(null, null);
        }
        private void ViewModel_OnYardSubYardAddedd(object sender, YardItemEventArgs e)
        {
            //Find Node of yard
            TreeNode node = _yardNodeDict[e.Yard].Nodes["Sub Yards"];

            //Update
            var y = e.SubYard;
            var sub_node = node.Nodes.Add(GenerateTreeFrom(y));
            Draw_Yard_Click(null, null);
        }
        private void ViewModel_OnYardSubYardDeleted(object sender, YardItemEventArgs e)
        {
            //Find Node of yard
            TreeNode node = _yardNodeDict[e.Yard].Nodes["Sub Yards"];

            //Update
            int index = e.Index;
            node.Nodes.RemoveAt(index);
            this._vm.CurYard = null;
            Draw_Yard_Click(null, null);
        }
        #endregion

        #region Menu
        private void Menu_New_Click(object sender, EventArgs e)
        {
            _vm.CreateNewYard();
            //_yard = new Yard();
            //_curYard = _yard;
            //Draw_TreeView(_yard);
            //this.propertyGrid1.SelectedObject = _yard.Info;
        }
        private void Menu_Open_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.InitialDirectory = @"D:\MyCode\ASU-Project\Sample-MARKHAM";
            openFileDialog.Filter = "YAML files (*.yml)|*.yml|All files (*.*)|*.*";
            openFileDialog.FilterIndex = 2;
            openFileDialog.RestoreDirectory = true;

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                // 获取选定文件的路径
                string filePath = openFileDialog.FileName;
                _vm.ReadYardFromYaml(filePath);
            }
        }
        private void Menu_Save_Click(object sender, EventArgs e)
        {
            if (this._vm.Path == string.Empty)
            {
                // Displays a SaveFileDialog so the user can save the Image
                // assigned to Button2.
                SaveFileDialog saveFileDialog1 = new SaveFileDialog();
                saveFileDialog1.Filter = "YAML Image|*.yml";
                saveFileDialog1.Title = "Save an YAML File";
                saveFileDialog1.ShowDialog();

                // If the file name is not an empty string open it for saving.
                if (saveFileDialog1.FileName != "")
                {
                    this._vm.Path = saveFileDialog1.FileName;
                }
                else
                {
                    return;
                }
            }

            var serializer = new SerializerBuilder()
                .WithNamingConvention(UnderscoredNamingConvention.Instance)
                .Build();
            var yaml = serializer.Serialize(this._vm.Yard);
            File.WriteAllText(this._vm.Path, yaml);
        }
        private void Menu_Save_As_Click(object sender, EventArgs e)
        {
            // Displays a SaveFileDialog so the user can save the Image
            // assigned to Button2.
            SaveFileDialog saveFileDialog1 = new SaveFileDialog();
            saveFileDialog1.Filter = "YAML Image|*.yml";
            saveFileDialog1.Title = "Save an YAML File";
            saveFileDialog1.ShowDialog();

            // If the file name is not an empty string open it for saving.
            if (saveFileDialog1.FileName != "")
            {
                var serializer = new SerializerBuilder()
                    .WithNamingConvention(UnderscoredNamingConvention.Instance)
                    .Build();
                var yaml = serializer.Serialize(this._vm.Yard);

                File.WriteAllText(saveFileDialog1.FileName, yaml);
                this._vm.Path = saveFileDialog1.FileName;
            }
        }
        private void Menu_Load_Map_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.InitialDirectory = @"D:\MyCode\ASU-Project\Sample-MARKHAM";
            openFileDialog.Filter = "PBF files (*.pbf)|*.pbf|OSM files (*.osm)|*.osm|All files (*.*)|*.*";
            openFileDialog.FilterIndex = 2;
            openFileDialog.RestoreDirectory = true;

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                // 获取选定文件的路径
                string filePath = openFileDialog.FileName;
                string ext = System.IO.Path.GetExtension(filePath);

                // 读取文件内容
                using (var fileStream = File.OpenRead(filePath))
                {
                    // create source stream.
                    OsmStreamSource source = null; // = new PBFOsmStreamSource(fileStream);

                    if (ext == ".pbf")
                    {
                        source = new PBFOsmStreamSource(fileStream);
                    }
                    else if (ext == ".osm")
                    {
                        source = new XmlOsmStreamSource(fileStream);
                    }
                    else
                    {
                        return;
                    }

                    // filter all powerlines and keep all nodes.
                    var filtered = from osmGeo in source
                                   where osmGeo.Type == OsmSharp.OsmGeoType.Node ||
                                    (osmGeo.Type == OsmSharp.OsmGeoType.Way && osmGeo.Tags != null) // && osmGeo.Tags.Contains("power", "line"))
                                   select osmGeo;

                    // convert to complete stream.
                    // WARNING: nodes that are partof powerlines will be kept in-memory.
                    //          it's important to filter only the objects you need **before** 
                    //          you convert to a complete stream otherwise all objects will 
                    //          be kept in-memory.
                    var features = filtered.ToFeatureSource();

                    // filter out only linestrings.
                    var lineStrings = from feature in features
                                      where feature.Geometry is LineString
                                      select feature;

                    double x = 0; double y = 0;
                    int n = 1;
                    foreach (var feature in lineStrings)
                    {
                        x = x + 1 / n * feature.Geometry.Centroid.X;
                        y = y + 1 / n * feature.Geometry.Centroid.Y;
                        n++;
                        GMapRoute route = new GMapRoute(Guid.NewGuid().ToString());
                        route.Stroke = new Pen(Color.Gray, 1);
                        var coordinates = feature.Geometry.Coordinates;
                        foreach (var coordinate in coordinates)
                        {
                            route.Points.Add(new PointLatLng(coordinate.Y, coordinate.X));
                        }
                        //将route添加到图层
                        osmLayer.Routes.Add(route);
                    }

                    var polygons = from feature in features
                                   where feature.Geometry is Polygon
                                   select feature;

                    foreach (var feature in polygons)
                    {
                        x = x + 1 / n * feature.Geometry.Centroid.X;
                        y = y + 1 / n * feature.Geometry.Centroid.Y;
                        n++;

                        List<PointLatLng> points = new List<PointLatLng>();
                        foreach (var coordinate in feature.Geometry.Coordinates)
                        {
                            points.Add(new PointLatLng(coordinate.Y, coordinate.X));
                        }

                        GMapPolygon polygon = new GMapPolygon(points, Guid.NewGuid().ToString());
                        polygon.Fill = new SolidBrush(Color.FromArgb(50, Color.Red));
                        polygon.Stroke = new Pen(Color.Red, 1);
                        osmLayer.Polygons.Add(polygon);
                    }
                    this.gMapControl1.Position = new PointLatLng(y, x);
                }
            }
        }
        #endregion

        #region Map Toolbox
        private void Zoom_In_Click(object sender, EventArgs e)
        {
            this.gMapControl1.Zoom += 1;
        }
        private void Zoom_Out_Click(object sender, EventArgs e)
        {
            this.gMapControl1.Zoom -= 1;
        }
        private void Map_Bear_Left_Click(object sender, EventArgs e)
        {
            this.gMapControl1.Bearing -= 10;
        }
        private void Map_Bear_Right_Click(object sender, EventArgs e)
        {
            this.gMapControl1.Bearing += 10;
        }
        private void Switch_Tiles_Visible_Click(object sender, EventArgs e)
        {
            if (gMapControl1.MapProvider != GMap.NET.MapProviders.EmptyProvider.Instance)
            {
                gMapControl1.MapProvider = GMap.NET.MapProviders.EmptyProvider.Instance;
            }
            else
            {
                gMapControl1.MapProvider = GMap.NET.MapProviders.BingOSMapProvider.Instance;
            }
            gMapControl1.Refresh();
        }

        private void InitMap()
        {
            this.gMapControl1.Overlays.Clear();

            //创建Node图层
            nodeLayer = new GMapOverlay("Mark");

            osmLayer = new GMapOverlay("OSM");


            this.gMapControl1.Overlays.Add(osmLayer);

            //将图层添加到地图
            this.gMapControl1.Overlays.Add(nodeLayer);
        }

        private void Draw_Yard_Click(object sender, EventArgs e)
        {
            nodeLayer.Clear();
            DrawYard(this._vm.CurYard);
        }
        private void DrawYard(Yard y)
        {
            if (y == null) return;
            foreach (var c in y.Connections)
            {
                DrawConnection(y, c);
            }
            foreach (var p in y.Points)
            {
                DrawNode(p);
            }
            DrawPolygon(y.Boundary);
            foreach (var sub in y.Yards)
            {
                DrawYard(sub);
            }
        }
        private void DrawNode(YPoint p)
        {
            //创建“marker”标记，设置其位于40.0，117.0，及箭头样式
            GMapMarkerCircle marker = new GMapMarkerCircle(new PointLatLng(p.Latitude, p.Longitude));
            if (p.Type == YPointType.gate_in || p.Type == YPointType.gate_out)
            {
                marker.Fill = new SolidBrush(Color.DarkGreen);
            }
            else
            {
                marker.Fill = new SolidBrush(Color.Yellow);
            }
            marker.Name = p.ToString();
            marker.ToolTipText = p.ToString();
            marker.ToolTip.Fill = new SolidBrush(Color.FromArgb(100, Color.Black));
            marker.ToolTip.Foreground = Brushes.White;
            marker.ToolTip.TextPadding = new Size(20, 20);
            //将标记添加到图层
            nodeLayer.Markers.Add(marker);


        }
        private void DrawConnection(Yard y, Connection c)
        {
            var p1 = y.GetPointById(c.FromPointId);// y.Points.FirstOrDefault(i => i.Id == c.FromPointId);
            var p2 = y.GetPointById(c.ToPointId); //y.Points.FirstOrDefault(i => i.Id == c.ToPointId);

            if (p1 == null || p2 == null) return;

            GMapRoute route1 = new GMapRoute("route1");
            if(c.Type == YConnectionType.bridge)  //设置route的颜色和粗细
            {
                route1.Stroke = new Pen(Color.Blue, 5);
            }
            else
            {
                route1.Stroke = new Pen(Color.Black, 5);
            }
           
            //向route中添加点
            route1.Points.Add(new PointLatLng(p1.Latitude, p1.Longitude));
            route1.Points.Add(new PointLatLng(p2.Latitude, p2.Longitude));
            //将route添加到图层
            nodeLayer.Routes.Add(route1);
        }
        private void DrawPolygon(IEnumerable<BoundaryPoint> points)
        {
            List<PointLatLng> temp = new List<PointLatLng>();
            foreach (var p in points)
            {
                temp.Add(new PointLatLng(p.Latitude, p.Longitude));
                GMapMarkerCircle marker = new GMapMarkerCircle(new PointLatLng(p.Latitude, p.Longitude));
                marker.IsHitTestVisible = false;
                marker.Radius = 5;
                marker.Fill = new SolidBrush(Color.DarkRed);
                //将标记添加到图层
                nodeLayer.Markers.Add(marker);
            }

            if (points == null || points.Count() < 3) return;
            GMapPolygon polygon = new GMapPolygon(temp, Guid.NewGuid().ToString());
            polygon.Fill = new SolidBrush(Color.FromArgb(25, Color.Red));
            polygon.Stroke = new Pen(Color.Red, 1);
            nodeLayer.Polygons.Add(polygon);
        }

        GMapMarkerCircle _selectedMarker;

        private void Add_Yard_Point_Click(object sender, EventArgs e)
        {
            _vm.AddNewPointCommand.Execute((this.gMapControl1.Position.Lat,
                this.gMapControl1.Position.Lng));
        }
        private void Add_Boundary_Point_Click(object sender, EventArgs e)
        {
            _vm.AddBoundaryPointCommand.Execute((this.gMapControl1.Position.Lat,
                this.gMapControl1.Position.Lng));
        }

        #endregion

        #region TreeView

        private void Refresh_Outline_Click(object sender, EventArgs e)
        {
            Draw_TreeView(this._vm.Yard);
        }

        private TreeNode GenerateTreeFrom(Yard yard)
        {
            TreeNode root = new TreeNode($"Yard {yard.Info.Name} {yard.Info.Id}") { Tag = yard  };
            _yardNodeDict.Add(yard,root); //update the dict

            TreeNode pointsRootNode = root.Nodes.Add("Points", "Points");
            pointsRootNode.Tag = yard;
            TreeNode connectionRootNode = root.Nodes.Add("Connections", "Connections");
            connectionRootNode.Tag = yard;
            TreeNode boundaryRootNode = root.Nodes.Add("Boundary", "Boundary");
            boundaryRootNode.Tag = yard;
            TreeNode SubYardRootNode = root.Nodes.Add("Sub Yards", "Sub Yards");
            SubYardRootNode.Tag = yard;
            foreach (var p in yard.Points)
            {
                var node = pointsRootNode.Nodes.Add(p.ToString());
                node.Tag = p;
            }
            foreach (var c in yard.Connections)
            {
                var node = connectionRootNode.Nodes.Add(c.ToString());
                node.Tag = c;
            }
            foreach (var y in yard.Yards)
            {
                SubYardRootNode.Nodes.Add(GenerateTreeFrom(y));
            }
            foreach(var b in yard.Boundary)
            {
                var node = boundaryRootNode.Nodes.Add(b.ToString());
                node.Tag = b;
            }
            return root;
        }

        private void Draw_TreeView(Yard yard)
        {
            _yardNodeDict.Clear();
            treeView1.Nodes.Clear();
            treeView1.Nodes.Add(GenerateTreeFrom(yard));
            treeView1.ExpandAll();
        }

        private void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Node.Tag is Yard y)
            {
                this.propertyGrid1.SelectedObject = y.Info;
                this._vm.CurYard = y;
            }
            else if (e.Node.Tag is YPoint p)
            {
                this.propertyGrid1.SelectedObject = p;
                this.gMapControl1.Position = this.gMapControl1.Position = new PointLatLng(p.Latitude, p.Longitude);
            }
            else if (e.Node.Tag is Connection c)
            {
                this.propertyGrid1.SelectedObject = c;
            }
        }

        #region Disable Expand / Collapse On Double Click
        int nodeClicks = 0;
        TreeViewHitTestInfo hitInfo = null;
        private void treeView_MouseDown(object sender, MouseEventArgs e)
        {
            hitInfo = treeView1.HitTest(e.Location);
            nodeClicks = e.Clicks;
        }
        private void treeView_BeforeCollapse(object sender, TreeViewCancelEventArgs e)
        {
            if (nodeClicks > 1 && hitInfo.Location == TreeViewHitTestLocations.Label)
            {
                e.Cancel = true;
            }
        }
        private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            if (nodeClicks > 1 && hitInfo.Location == TreeViewHitTestLocations.Label)
            {
                e.Cancel = true;
            }
        }
        #endregion 

        private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Button != MouseButtons.Right) return;
            if (e.Node.Parent == null || e.Node == null) return;
            if(e.Node.Text == "Points" || e.Node.Text == "Connections" || e.Node.Text == "Yards" || e.Node.Text == "Boundary")
            {
                treeView1.SelectedNode = e.Node;
                contextMenuStrip1.Show(e.X, e.Y);
            }
        }
        private void ContextMenu_Add_Click(object sender, EventArgs e)
        {
            if(treeView1.SelectedNode.Tag is Yard superYard)
            {
                if (treeView1.SelectedNode?.Text == "Points")
                {
                    _vm.AddNewPointCommand.Execute((this.gMapControl1.Position.Lat,
                        this.gMapControl1.Position.Lng));
                }
                else if (treeView1.SelectedNode?.Text == "Connections")
                {
                    _vm.AddConnectionCommand.Execute(null);
                }
                else if (treeView1.SelectedNode?.Text == "Sub Yards")
                {
                    this._vm.AddNewYardCommand.Execute(superYard);
                }
                else if (treeView1.SelectedNode?.Text == "Boundary")
                {
                    _vm.AddBoundaryPointCommand.Execute((this.gMapControl1.Position.Lat,
                        this.gMapControl1.Position.Lng));
                }
                //Draw_TreeView(_yard);
            }
        }
        private void Delete_Item_Click(object sender, EventArgs e)
        {
            var node = treeView1.SelectedNode;
            var parent = node.Parent;
            if (parent == null) { return;  }
            if (parent.Text == "Points" )
            {
                if(parent.Tag is Yard y && node.Tag is YPoint p)
                {
                    y.Points.Remove(p);
                }
            }
            else if (parent.Text == "Connections")
            {
                if (parent.Tag is Yard y && node.Tag is Connection c)
                {
                    y.Connections.Remove(c);
                }
            }
            else if (parent.Text == "Sub Yards")
            {
                if (parent.Tag is Yard y && node.Tag is Yard s)
                {
                    y.Yards.Remove(s);
                }
            }
            else if (parent.Text == "Boundary")
            {
                if (parent.Tag is Yard y && node.Tag is BoundaryPoint b)
                {
                    y.Boundary.Remove(b);
                }
            }
        }

        #endregion


    }
}
